package com.asura.app.library.imageload;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PictureDrawable;
import android.net.Uri;
import android.widget.ImageView;

import com.asura.app.library.glide.svg.SvgDecoder;
import com.asura.app.library.glide.svg.SvgDrawableTranscoder;
import com.asura.app.library.glide.svg.SvgSoftwareLayerSetter;
import com.asura.app.library.utils.FileUtils;
import com.bumptech.glide.DrawableRequestBuilder;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory;
import com.bumptech.glide.load.model.StreamEncoder;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.load.resource.file.FileToStreamDecoder;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.target.Target;
import com.caverock.androidsvg.SVG;
import com.orhanobut.logger.Logger;

import java.io.File;
import java.io.InputStream;

/**
 * Created by Asura on 2017/11/29.
 */

public class GlideImageLoader implements ImageLoader {
    private Context appContext;

    public GlideImageLoader(Context context) {
        appContext = context.getApplicationContext();
    }

    @Override
    public void load(Context context, ImageView imageView, ImageLoadOptions options, ImageLoadListener imageLoadListener) {
        Uri uri = getUri(options);
        if (uri == null) {
            Logger.w("there is no image address found");
            return;
        }
        if (uri.getPath().endsWith(".svg")) {
            loadSvg(context, imageView, options, uri, imageLoadListener);
            return;
        }
        DiskCacheStrategy diskCacheStrategy;
        if (uri.getPath().endsWith(".gif")) {
            diskCacheStrategy = DiskCacheStrategy.SOURCE;
        } else if (uri.getScheme().equalsIgnoreCase("http") || uri.getScheme().equalsIgnoreCase("https")) {
            diskCacheStrategy = DiskCacheStrategy.ALL;
        } else {
            diskCacheStrategy = DiskCacheStrategy.RESULT;
        }
        DrawableRequestBuilder<Uri> requestBuilder = Glide.with(context)
                .load(uri)
                .placeholder(options.getPlaceHolder())
                .error(options.getError())
                .priority(shiftPriority(options.getPriority()))
                .skipMemoryCache(!options.isMemoryCache())
                .diskCacheStrategy(diskCacheStrategy);
        //缩略图
        if (options.getThumbnail() != null) {
            DrawableRequestBuilder<String> thumbnailRequest = Glide.with(context).load(options.getUrl()).diskCacheStrategy(DiskCacheStrategy.ALL);
            requestBuilder.thumbnail(thumbnailRequest);
        }
        if (options.getWidth() != ImageLoadOptions.UNKNOW && options.getHeight() != ImageLoadOptions.UNKNOW) {
            int width = options.getWidth();
            int height = options.getHeight();
            width = width == ImageLoadOptions.ORIGIN ? Target.SIZE_ORIGINAL : width;
            height = height == ImageLoadOptions.ORIGIN ? Target.SIZE_ORIGINAL : height;
            requestBuilder.override(width, height).centerCrop();
        }
        if (imageLoadListener != null) {
            requestBuilder.listener(new RequestListener<Uri, GlideDrawable>() {
                @Override
                public boolean onException(Exception e, Uri model, Target<GlideDrawable> target, boolean isFirstResource) {
                    if (!isFirstResource) {
                        imageLoadListener.onLoadFail(e);
                    }
                    return false;
                }

                @Override
                public boolean onResourceReady(GlideDrawable resource, Uri model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                    if (!isFirstResource) {
                        imageLoadListener.onLoadSuccess();
                    }
                    return false;
                }
            });
        }
        requestBuilder.into(imageView);
    }


    @Override
    public void fetch(Context context, ImageLoadOptions options, ImageLoadListener imageLoadListener) {
        if (options.getUrl() == null) {
            throw new IllegalArgumentException("this function is only for network image");
        }
        Glide.with(context)
                .load(options.getUrl())
                .downloadOnly(new SimpleTarget<File>() {
                    @Override
                    public void onResourceReady(File resource, GlideAnimation<? super File> glideAnimation) {
                        Glide.clear(this);
                        if (imageLoadListener != null) {
                            imageLoadListener.onLoadSuccess();
                        }
                    }

                    @Override
                    public void onLoadFailed(Exception e, Drawable errorDrawable) {
                        if (imageLoadListener != null) {
                            imageLoadListener.onLoadFail(e);
                        }
                    }
                });
    }

    @Override
    public void cancel(Context context, ImageView imageView) {
        Glide.clear(imageView);
    }

    @Override
    public long cacheSize() {
        try {
            return FileUtils.getFolderSize(new File(appContext.getCacheDir() + "/" + InternalCacheDiskCacheFactory.DEFAULT_DISK_CACHE_DIR));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    @Override
    public void clearCache() {
        Glide.get(appContext).clearDiskCache();
    }


    private void loadSvg(Context context, ImageView imageView, ImageLoadOptions options, Uri uri, ImageLoadListener imageLoadListener) {
        Glide.with(context)
                .using(Glide.buildStreamModelLoader(Uri.class, context), InputStream.class)
                .from(Uri.class)
                .as(SVG.class)
                .transcode(new SvgDrawableTranscoder(), PictureDrawable.class)
                .sourceEncoder(new StreamEncoder())
                .cacheDecoder(new FileToStreamDecoder<SVG>(new SvgDecoder()))
                .decoder(new SvgDecoder())
                .animate(android.R.anim.fade_in)
                .listener(new SvgSoftwareLayerSetter<Uri>() {
                    @Override
                    public boolean onException(Exception e, Uri model, Target<PictureDrawable> target, boolean isFirstResource) {
                        imageLoadListener.onLoadFail(e);
                        return super.onException(e, model, target, isFirstResource);
                    }

                    @Override
                    public boolean onResourceReady(PictureDrawable resource, Uri model, Target<PictureDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                        imageLoadListener.onLoadSuccess();
                        return super.onResourceReady(resource, model, target, isFromMemoryCache, isFirstResource);
                    }
                })
                .placeholder(options.getPlaceHolder())
                .error(options.getError())
                .priority(shiftPriority(options.getPriority()))
                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                .skipMemoryCache(!options.isMemoryCache())
                .load(uri)
                .into(imageView);
    }

    private Uri getUri(ImageLoadOptions options) {
        if (options.getUrl() != null) {
            return Uri.parse(options.getUrl());
        } else if (options.getPath() != null) {
            return Uri.fromFile(new File(options.getPath()));
        } else if (options.getResId() != 0) {
            return Uri.parse("android.resource://" + appContext.getPackageName() + "/" + options.getResId());
        }
        return null;
    }

    private com.bumptech.glide.Priority shiftPriority(Priority priority) {
        switch (priority) {
            case LOW:
                return com.bumptech.glide.Priority.LOW;
            case HIGH:
                return com.bumptech.glide.Priority.HIGH;
            case NORMAL:
                return com.bumptech.glide.Priority.NORMAL;
        }
        return com.bumptech.glide.Priority.NORMAL;
    }
}
